﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.IO.Filesystem.Ntfs;
using System.IO;
using System.Windows.Forms;
using DevComponents.AdvTree;
using DevComponents.DotNetBar;
using System.Threading.Tasks;

namespace AcceleratorSearch
{
    public static class SearchCore
    {
        enum NodeAttribute
        {
            Name = 0, Path = 1, Size = 2, UpdateDate = 3, CreateDate = 4, AccessDate = 5
        }

        private static FormMain formMain;
        private static BackgroundWorker loader = new BackgroundWorker();
        //public static Dictionary<string,NtfsReader> NTFSList = new Dictionary<string, NtfsReader>();
        //public static Dictionary<string, List<INode>> Searcher = new Dictionary<string, List<INode>>(); 
        public static List<INode> Searcher = new List<INode>();
        public static List<ListViewItem> CurrentCacheItemsSource
        {
            get;
            set;
        }
        public static string[] GetAllDisks()
        {
            string[] diskPaths = System.IO.Directory.GetLogicalDrives(); //也可以通过DriveInfo.GetDrives()获取
            for (int i = 0; i < diskPaths.Length; i++)
            {
                diskPaths[i] = FormatDiskLabel(diskPaths[i]);
            }
            return diskPaths;
        }

        private static string FormatDiskLabel(string diskPath)
        {
            return diskPath.Replace(":\\", "");
        }

        /// <summary>
        /// 取得所有驱动器信息（仅限NTFS）
        /// </summary>
        /// <returns></returns>
        public static List<DriveInfo> GetAllDriveInfos()
        {
            string[] disks = GetAllDisks();
            List<DriveInfo> driveInfos = new List<DriveInfo>();

            driveInfos.Add(new DriveInfo("D"));
            return driveInfos;

            foreach (var disk in disks)
            {
                try
                {
                    DriveInfo d = new DriveInfo(disk);
                    if (d.DriveFormat.Contains("NTFS"))
                    {
                        driveInfos.Add(d);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    continue;
                }
            }
            return driveInfos;
        }

        public static void Init(FormMain form)
        {
            formMain = form;
            Refresh();
        }

        public static void Refresh()
        {
            if (!loader.IsBusy)
            {
                loader = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
                loader.DoWork += loader_DoWork;
                loader.ProgressChanged += loader_ProgressChanged;
                loader.RunWorkerCompleted += loader_RunWorkerCompleted;
                loader.RunWorkerAsync();
            }

        }

        static void loader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //foreach (var itemList in Searcher.Values)
            //{
            //    foreach (var item in itemList)
            //    {
            //        Node nod = new Node(item.Name);

            //        nod.Cells.Add(new Cell(item.FullName));
            //        nod.Cells.Add(new Cell(Util.CountSize((long)item.Size)));
            //        nod.Cells.Add(new Cell(item.LastChangeTime.ToShortDateString()));
            //        nod.Cells.Add(new Cell(item.CreationTime.ToShortDateString()));
            //        nod.Cells.Add(new Cell(item.LastAccessTime.ToShortDateString()));
            //        formMain.listResult.Invoke(new MethodInvoker(() => formMain.listResult.Nodes.Add(nod)));
            //    }
            //}
            //foreach (var nodes in Searcher.Values)
            //{
            //    formMain.listResult.Invoke(new MethodInvoker(() => formMain.listResult.Nodes.AddRange(nodes.ToArray())));
            //}

            loader = null;
            GC.Collect();
        }

        static void loader_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            formMain.lblState.Invoke(new MethodInvoker(() => { formMain.lblState.Text = "正在分析：" + e.UserState.ToString(); }));
            formMain.progressState.Invoke(new MethodInvoker(() =>
            {
                formMain.progressState.Value = e.ProgressPercentage;
            }));
        }

        private static void loader_DoWork(object sender, DoWorkEventArgs e)
        {
            var allDrive = GetAllDriveInfos();
            int sum = allDrive.Count * 2;
            float i = 1.0f;
            foreach (var driveInfo in allDrive)
            {
                string label = FormatDiskLabel(driveInfo.Name);
                Console.WriteLine("Analysing " + label.ToUpper() + " " + driveInfo.VolumeLabel);
                ((BackgroundWorker)sender).ReportProgress((int)((i / sum) * 100), label);
                i++;
                using (var reader = new NtfsReader(driveInfo, RetrieveMode.StandardInformations))
                {
                    //ConvertNodes(reader.GetNodes(driveInfo.Name));
                    Searcher.AddRange(reader.GetNodes(driveInfo.Name));
                }
                formMain.listResult.Invoke(new MethodInvoker(() => { formMain.listResult.VirtualListSize = Searcher.Count; }));
                ((BackgroundWorker)sender).ReportProgress((int)((i / sum) * 100), label);
                i++;

            }
            ((BackgroundWorker)sender).ReportProgress((int)(i / sum) * 100, "分析已完成");
        }

        /// <summary>
        /// 将NTFS节点转为列表节点
        /// </summary>
        /// <param name="iNodes"></param>
        /// <returns></returns>
        private static void ConvertNodes(List<INode> iNodes)
        {
            //Node[] nodes = new Node[iNodes.Count];
            //List的元素数默认是2的倍数，超额后会扩增一倍但需要将原来的元素复制进新List!
            if (CurrentCacheItemsSource == null || CurrentCacheItemsSource.Count == 0)
            {
                CurrentCacheItemsSource = new List<ListViewItem>(iNodes.Count);
            }

            Parallel.For(0, iNodes.Count,new ParallelOptions { MaxDegreeOfParallelism = 5}, (i) =>
            {
                var nod = CreateListViewItemFromNode(iNodes, i);
                CurrentCacheItemsSource.Add(nod);
                if (i % 5000 == 0)
                {
                    formMain.listResult.Invoke(new MethodInvoker(() => { formMain.listResult.VirtualListSize = CurrentCacheItemsSource.Count; }));
                }
                //nod.SubItems.Add();
                //    //nod.Cells.Add(new Cell(Util.CountSize((long)iNodes[i].Size)));
                //    nod.Cells.Add(new Cell(iNodes[i].LastChangeTime.ToShortDateString()));
                //    nod.Cells.Add(new Cell(iNodes[i].CreationTime.ToShortDateString()));
                //    nod.Cells.Add(new Cell(iNodes[i].LastAccessTime.ToShortDateString()));
                //    nodes[i] = nod;

                //formMain.listResult.Invoke(new MethodInvoker(() => formMain.listResult.Items.Add(nodes[i])));
            });
            
            formMain.listResult.Invoke(new MethodInvoker(() => { formMain.listResult.VirtualListSize = CurrentCacheItemsSource.Count; }));
            //foreach (var iNode in iNodes)
            //{
            //    Node nod = new Node(iNode.Name);
            //    nod.Cells.Add(new Cell(iNode.FullName));
            //    //nod.Cells.Add(new Cell(Util.CountSize((long)iNode.Size)));
            //    nod.Cells.Add(new Cell(iNode.LastChangeTime.ToShortDateString()));
            //    nod.Cells.Add(new Cell(iNode.CreationTime.ToShortDateString()));
            //    nod.Cells.Add(new Cell(iNode.LastAccessTime.ToShortDateString()));
            //    nodes.Add(nod);
            //    //formMain.listResult.Invoke(new MethodInvoker(() => formMain.listResult.Nodes.Add(nod)));
            //}

        }

        public static ListViewItem CreateListViewItemFromNode(List<INode> iNodes, int i)
        {
            ListViewItem nod = new ListViewItem();
            nod.Name = iNodes[i].Name;
            nod.SubItems.AddRange(new[]
            {
                (iNodes[i].Name),
                (iNodes[i].FullName),
                Util.CountSize((iNodes[i].Size)),
                iNodes[i].LastChangeTime.ToShortDateString(),
                iNodes[i].CreationTime.ToShortDateString(),
                iNodes[i].LastAccessTime.ToShortDateString()
            });
            return nod;
        }
    }
}
